/*
 *  Copyright 2009 Allan Lykke Christensen.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package dk.i2m.netbeans.modules.doxia;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.apache.maven.doxia.Converter;
import org.apache.maven.doxia.DefaultConverter;
import org.apache.maven.doxia.wrapper.InputReaderWrapper;
import org.apache.maven.doxia.wrapper.OutputStreamWrapper;
import org.codehaus.plexus.ContainerConfiguration;
import org.codehaus.plexus.DefaultContainerConfiguration;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.PlexusContainerException;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
import org.openide.util.Exceptions;

/**
 * Static library containing helper methods for working with the APT format.
 *
 * @author Allan Lykke Christensen
 */
public class AptUtils {

    private static final String APT_FORMAT = "apt";
    private static final String XHTML_FORMAT = "xhtml";

    public AptUtils() {
        throw new UnsupportedOperationException(
                "AptUtils is a static helper utility");
    }

    /**
     * Converts an APT String to XHTML.
     *
     * @param apt
     *          APT formatted String
     * @return XHTML formatted String
     * @throws InvalidFormatException
     *          If the APT format was invalid
     */
    public static final String aptToXhtml(String apt) throws
            InvalidFormatException {

        Converter converter = reflectAndMeditate(new DefaultConverter());

        Reader reader = new StringReader(apt);
        OutputStream os = new ByteArrayOutputStream();

        InputReaderWrapper input = InputReaderWrapper.valueOf(reader,
                APT_FORMAT, converter.getInputFormats());
        OutputStreamWrapper output = OutputStreamWrapper.valueOf(os,
                XHTML_FORMAT, "UTF-8", converter.getOutputFormats());

        try {
            converter.convert(input, output);
        } catch (Exception ex) {
            throw new InvalidFormatException(ex);
        }
        return os.toString();
    }

    static Converter reflectAndMeditate(DefaultConverter def) {
        try {
            Field fld = def.getClass().getDeclaredField("plexus");
            fld.setAccessible(true);
            fld.set(def, startPlexusContainer());
        } catch (IllegalArgumentException ex) {
            Exceptions.printStackTrace(ex);
        } catch (IllegalAccessException ex) {
            Exceptions.printStackTrace(ex);
        } catch (PlexusContainerException ex) {
            Exceptions.printStackTrace(ex);
        } catch (DuplicateRealmException ex) {
            Exceptions.printStackTrace(ex);
        } catch (NoSuchFieldException ex) {
            Exceptions.printStackTrace(ex);
        } catch (SecurityException ex) {
            Exceptions.printStackTrace(ex);
        }
        return def;
    }

    /**
     * Start the Plexus container.
     *
     * @throws PlexusContainerException if any
     */
    static PlexusContainer startPlexusContainer()
            throws PlexusContainerException, DuplicateRealmException {
        Map context = new HashMap();
        context.put("basedir", new File("").getAbsolutePath()); //strange, oh well..

        ContainerConfiguration containerConfiguration =
                new DefaultContainerConfiguration();
        containerConfiguration.setName("Doxia");
        containerConfiguration.setContext(context);

        ClassWorld world = new ClassWorld();
        world.newRealm("plexus.core", AptUtils.class.getClassLoader()); //NOI18N

        containerConfiguration.setClassWorld(world);

        return new DefaultPlexusContainer(containerConfiguration);
    }
}
